package com.hrpc.protection;

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 手写熔断器
 */
public class CircuitBreaker {
    //标准应该有三种状态：关闭、开启、半开启
    //现在为了方便，只用两种：关闭、开启
    private volatile boolean isOpen=false;
    //需要搜索指标、异常的数量、比例
    private AtomicInteger requestCount=new AtomicInteger(0);
    //统计异常的请求数
    private AtomicInteger errorRequest=new AtomicInteger(0);
    //异常的阈值
    private int maxErrorRequest;
    //比例
    private float maxErrorRate;

    /**
     * 需要指定最大异常请求数和最大错误比例
     * @param maxErrorRequest
     * @param maxErrorRate
     */
    public CircuitBreaker(int maxErrorRequest, float maxErrorRate) {
        this.maxErrorRequest = maxErrorRequest;
        this.maxErrorRate = maxErrorRate;
    }
    //断路器的核心方法，判断是否开启
    public boolean isBreak(){
        //如果已经打开就直接返回true
        if(isOpen == true){
            return true;
        }
        //需要判断数据指标是否满足当前的阈值
        if (errorRequest.get() > maxErrorRequest){
            this.isOpen=true;
            return true;
        }
        if (errorRequest.get()>0 && requestCount.get()>0 &&
                errorRequest.get()/(float)requestCount.get()>=maxErrorRate ){
            this.isOpen=true;
            return true;
        }
        return false;
    }

    //每次发生请求或是发生异常，应该进行记录
    public void recordRequest(){
        this.requestCount.getAndIncrement();
    }
    public void recordErrorRequest(){
        this.errorRequest.getAndIncrement();
    }

    /**
     * 重置熔断器
     */
    public void reSet(){
        this.isOpen=false;
        this.requestCount.set(0);
        this.errorRequest.set(0);
    }

    public static void main(String[] args) {
        CircuitBreaker circuitBreaker=new CircuitBreaker(3,0.2F);
        for (int i = 0; i < 1000; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            circuitBreaker.recordRequest();
            int num=new Random().nextInt(100);
            if (num > 70){
                circuitBreaker.recordErrorRequest();
            }
            boolean isBreak = circuitBreaker.isBreak();
            String result=isBreak ? "断路器阻塞了请求" : "断路器放行了请求";
            System.out.println(result);
        }
        new Thread(() ->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            circuitBreaker.reSet();
        }).start();
    }
}
